package com.fll.codeworld.thread;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;

/**
 * @author fll
 * @description
 * @date 2022/1/14 15:58
 */
@Slf4j
@Service
public class AsyncService {
    /**
     * 指定使用beanname为doSomethingExecutor的线程池
     * @param message
     * @return
     */
    @Async("doSomethingExecutor")
    public String doSomething(String message) {
        log.info("do something, message={}", message);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            log.error("do something error: ", e);
        }
        return message;
    }
    @Async("doSomethingExecutor")
    public CompletableFuture<String> doSomething1(String message) throws InterruptedException {
        log.info("do something1: {}", message);
        Thread.sleep(1000);
        return CompletableFuture.completedFuture("do something1: " + message);
    }

    @Async("doSomethingExecutor")
    public CompletableFuture<String> doSomething2(String message) throws InterruptedException {
        log.info("do something2: {}", message);
        Thread.sleep(1000);
        return CompletableFuture.completedFuture("; do something2: " + message);
    }

    @Async("doSomethingExecutor")
    public CompletableFuture<String> doSomething3(String message) throws InterruptedException {
        log.info("do something3: {}", message);
        Thread.sleep(1000);
        return CompletableFuture.completedFuture("; do something3: " + message);
    }


    /**
     * (1)某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为n new CountDownLatch(n) ，
     * 每当一个任务线程执行完毕，就将计数器减1 countdownlatch.countDown()，当计数器的值变为0时，
     * 在CountDownLatch上 await() 的线程就会被唤醒。一个典型应用场景就是启动一个服务时，主线程需要等待多个组件加载完毕，之后再继续执行.
     * (2)实现多个线程开始执行任务的最大并行性。注意是并行性，不是并发，强调的是多个线程在某一时刻同时开始执行。
     * 类似于赛跑，将多个线程放到起点，等待发令枪响，然后同时开跑。做法是初始化一个共享的CountDownLatch(1)，
     * 将其计数器初始化为1，多个线程在开始执行任务前首先 coundownlatch.await()，当主线程调用 countDown() 时，计数器变为0，
     * 多个线程同时被唤醒。
     */
    static class MyRunnable implements Runnable {

        private CountDownLatch countDownLatch;

        private CountDownLatch await;

        public MyRunnable(CountDownLatch countDownLatch, CountDownLatch await) {
            this.countDownLatch = countDownLatch;
            this.await = await;
        }

        @Override
        public void run() {
            try {
                countDownLatch.await();
                System.out.println("子线程" +Thread.currentThread().getName()+ "处理自己事情");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                await.countDown();
            }

        }
    }

    public static void main(String[] args) throws InterruptedException {
            CountDownLatch countDownLatch = new CountDownLatch(1);
            CountDownLatch await = new CountDownLatch(6);

            for (int i=0; i< 7; i++) {
                new Thread(new MyRunnable(countDownLatch, await)).start();
            }
            System.out.println("主线程处理自己事情");
            Thread.sleep(3000);
            System.out.println("主线程处理结束");
            await.await();
            System.out.println("子线程处理完毕啦");
    }
}
